package com.zj.swagger.config;

import cn.zj.smart.util.javadoc.beans.JavaDoc;
import cn.zj.smart.util.javadoc.util.JavaDocUtil;
import com.fasterxml.classmate.ResolvedType;
import com.fasterxml.classmate.members.RawField;
import com.google.common.collect.Maps;
import cn.zj.smart.util.FileUtil;
import cn.zj.smart.util.StringUtil;
import io.swagger.models.Model;
import io.swagger.models.properties.Property;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import springfox.documentation.swagger2.mappers.ModelMapperImpl;
import com.zj.swagger.utils.ClassUtil;
import com.zj.swagger.beans.SwaggerConfig;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 覆写swagger的ModelMapper，实现：读取文件源码字段的注释当做swagger的字段描述
 */
@Slf4j
@Primary
@Configuration
@EnableConfigurationProperties(SwaggerConfig.class)
public class DocModelMapperImpl extends ModelMapperImpl {
	@Autowired
	private SwaggerConfig swaggerConfig;
	@Override
	public Map<String, Model> mapModels(Map<String, springfox.documentation.schema.Model> from) {
		Map<String, Model> map = super.mapModels(from);
		if (map != null) {
			Set<String> modelKeys = from.keySet();
			// 遍历所有的Model
			Map<String, JavaDoc> javaDocMap = getDocMap(swaggerConfig.getDocProjectPath());
			for (String key : modelKeys) {
				Model tm = map.get(key);
				// Model的属性
				Map<String, Property> properties = tm.getProperties();
				if (properties == null) {
					continue;
				}
				ResolvedType resolvedType = from.get(key).getType();
				List<RawField> memberFields = resolvedType.getMemberFields();
				Class clz = resolvedType.getErasedType();
				final String className = clz.getName();
				JavaDoc javaDoc;
				if (javaDocMap.containsKey(className)) {
					javaDoc = javaDocMap.get(className);
				} else {
					javaDoc = JavaDocUtil.getClassJavaDoc(clz);
					javaDocMap.put(className, javaDoc);
				}
				// 新的属性
				Map<String, Property> newProperties = Maps.newLinkedHashMap();
				for (RawField rawField : memberFields) {
					String name = rawField.getName();
					Property property = properties.remove(name);
					if (property == null) {
						continue;
					}
					newProperties.put(name, property);
					if (StringUtil.isNotBlank(property.getDescription())) {
						continue;
					}
					// 没有描述时，使用从源码获取的
					final String fieldDesc = javaDoc.getPropertyDocs().get(name);
					if (fieldDesc != null) {
						property.setDescription(fieldDesc);
					}
				}
				try {
					// 新的属性列表替换旧的
					Field propertiesField = ClassUtil.getDeclaredField(tm.getClass(), "properties", true);
					if (propertiesField != null) {
						propertiesField.set(tm, newProperties);
					}
				} catch (Exception e) {
					log.info("【SWAGGER】设置properties异常：{}", e.getMessage());
				}
			}
			FileUtil.writeObject(swaggerConfig.getDocProjectPath(),javaDocMap);
		}
		return map;
	}

	private Map<String, JavaDoc> getDocMap(String javaDocPath) {
		Object object = FileUtil.readObject(javaDocPath);
		if (null == object) {
			return new HashMap<>();
		}
		return (Map<String, JavaDoc>) object;
	}

}